package com.wyl.niupi.framework.util.jdkExt;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;

/**
 * 基于FFmpeg，视频、音频的工具类
 * @author 吴宇亮 on 2020/12/24 8:53
 */
public class _FFmpegUtil {

    private static final String IMAGE_TYPE = "png";;

    /**
     * 测试用例
     */
    public static void main(String[] args) throws Exception {
        getVideoImage("D:\\4.cfWorkspace\\svnRoot\\chat\\2020.11.13 openfire讨论总结\\3.聊天系统Demo\\openfire测试文件上传\\竖屏.mp4", "C:\\openfireServer\\fileSystem\\test");
        getVideoImage("D:\\4.cfWorkspace\\svnRoot\\chat\\2020.11.13 openfire讨论总结\\3.聊天系统Demo\\openfire测试文件上传\\横屏.mp4", "C:\\openfireServer\\fileSystem\\test");

//        Long videoDuration = getFileDuration(new File("D:\\4.cfWorkspace\\svnRoot\\chat\\2020.11.13 openfire讨论总结\\3.聊天系统Demo\\openfire测试文件上传\\音乐.mp3"));
//        String timeBySeconds = getTimeBySeconds(videoDuration.intValue());
//        System.out.println(timeBySeconds);
//
//        Long videoDuration1 = getFileDuration(new File("D:\\test\\video\\1.mp4"));
//        System.out.println(getTimeBySeconds(videoDuration1.intValue()));
//
//        System.out.println(getVideoImage("D:\\test\\video\\1.mp4", "D:\\test\\img\\"));
    }

    /**
     * 获取音频、视频时长（秒）
     * @param video 源视频文件
     * @return 时长（s）
     */
    public static long getFileDuration(File video) {
        long duration = 0L;
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);
        try {
            ff.start();
            //时长四舍五入取整
            //duration = ff.getLengthInTime() / (1000 * 1000);
            duration = new BigDecimal(ff.getLengthInTime()).divide(new BigDecimal(1000 * 1000), 0, RoundingMode.HALF_UP).longValue();
            ff.stop();
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        }
        return duration;
    }

    /**
     * 根据秒数，获取视频的时长
     * @param seconds 秒数
     * @return 如果秒数大于等于3600，则返回 hh:mm:ss，否则返回 mm:ss
     */
    public static String getTimeBySeconds(int seconds){
        int hour = 0, minute = 0, second = 0;
        second = seconds % 60;
        seconds -= second;
        if(seconds > 0) {
            seconds /= 60;
            minute = seconds % 60;
            seconds -= minute;
            if(seconds > 0) {
                hour = seconds / 60;
            }
        }
        String hourStr = hour < 10 ? "0" + hour : String.valueOf(hour);
        String minuteStr = minute < 10 ? "0" + minute : String.valueOf(minute);
        String secondStr = second < 10 ? "0" + second : String.valueOf(second);
        if(hour > 0){
            //输出hh:mm:ss
            return hourStr + ":" + minuteStr + ":" + secondStr;
        }else{
            //否则输出mm:ss
            return minuteStr + ":" + secondStr;
        }
    }

    /**
     * 截取视频第六帧的图片
     * @param filePath 视频的绝对路径
     * @param dir 文件存放的根目录，如：D:\test\img\
     * @return 图片的相对路径 如：pic\1.png
     */
    public static String getVideoImage(String filePath, String dir) throws FrameGrabber.Exception {
        return getVideoImage(new File(filePath), dir);
    }

    /**
     * 截取视频第六帧的图片
     * @param file 视频文件
     * @param dir 文件存放的根目录，如：D:\test\img
     * @return 图片的文件名 如：xxx.png
     */
    public static String getVideoImage(File file, String dir) throws FrameGrabber.Exception {
        FileUtil.mkdir(dir);
        String pngFileName = "";
        FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(file);
        ff.start(); //如果不开启start，则不会打印控制台信息
        String rotate_old = ff.getVideoMetadata("rotate");//视频旋转角度，可能是null
        int ffLength = ff.getLengthInFrames();
        Frame f = null;
        int i = 0;
        while (i < ffLength) {
            // 过滤前5帧，避免出现全黑的图片，依自己情况而定
            f = ff.grabFrame();
            if ((i > 5) && (f.image != null)) {
                break;
            }
            i++;
        }
        //生成图片的相对路径 例如：pic/uuid.png
        pngFileName = getPngFileName();
        //执行截图并放入指定位置
        String outputFileAbsolutePath = dir + File.separator + pngFileName;
        doExecuteFrame(f, outputFileAbsolutePath);
        //如果需要旋转
        if(StrUtil.isNotBlank(rotate_old)){
            int rotate = Integer.parseInt(rotate_old);
            rotatePhonePhoto(outputFileAbsolutePath, rotate);
        }
        ff.stop();
        return pngFileName;
    }

    /**
     * 截取视频第六帧的图片
     * @param url 网络视频地址
     * @param dir 文件存放的根目录，如：D:\test\img\
     * @return 图片的相对路径 例：pic/1.png
     */
    public static String getVideoImageByUrl(String url, String dir) throws Exception {
        InputStream videoInputStream = getVideoInputStream(url);
        String pngFileName = "";
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoInputStream);
        ff.start();
        int ffLength = ff.getLengthInFrames();
        Frame f;
        int i = 0;
        while (i < ffLength) {
            f = ff.grabFrame();
            //截取第6帧
            if ((i > 5) && (f.image != null)) {
                //生成图片的相对路径 例如：pic/uuid.png
                pngFileName = getPngFileName();
                //执行截图并放入指定位置
                doExecuteFrame(f, dir + pngFileName);
                break;
            }
            i++;
        }
        ff.stop();
        videoInputStream.close();
        return pngFileName;
    }

    /**
     * 将网络视频地址，转成输入流
     * @param videoUrl
     * @return 输入流
     */
    private static InputStream getVideoInputStream(String videoUrl) {
        // 1.下载网络文件
        try {
            URL url = new URL(videoUrl);
            //2.获取链接
            URLConnection conn = url.openConnection();
            //3.输入流
            InputStream inStream = conn.getInputStream();
            return inStream;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成图片的文件名
     * @return 生成图片的文件名
     */
    private static String getPngFileName() {
        return getUUID() + ".png";
    }

    /**
     * 生成唯一的uuid
     * @return uuid
     */
    private static String getUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }


    /**
     * 将视频的某一帧转换成图片，然后保存在outputFileAbsolutePath
     * @param frame 视频的某一帧
     * @param outputFileAbsolutePath 保存路径
     */
    private static void doExecuteFrame(Frame frame, String outputFileAbsolutePath) {
        String imagemat = IMAGE_TYPE;
        if (null == frame || null == frame.image) {
            return;
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage bi = converter.getBufferedImage(frame);
        File output = new File(outputFileAbsolutePath);
        try {
            ImageIO.write(bi, imagemat, output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 旋转照片
     * @param fullPath 要选择的图片
     * @param angel 旋转角度
     * @return
     */
    public static void rotatePhonePhoto(String fullPath, int angel) {
        BufferedImage src;
        try {
            src = ImageIO.read(new File(fullPath));
            int src_width = src.getWidth(null);
            int src_height = src.getHeight(null);

            int swidth = src_width;
            int sheight = src_height;

            if (angel == 90 || angel == 270) {
                swidth = src_height;
                sheight = src_width;
            }
            Rectangle rect_des = new Rectangle(new Dimension(swidth, sheight));
            BufferedImage res = new BufferedImage(rect_des.width, rect_des.height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2 = res.createGraphics();
            g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
            g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
            g2.drawImage(src, null, null);
            ImageIO.write(res, IMAGE_TYPE, new File(fullPath));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
